<?php
/**
 * 定时获取最新股票数据
 */
namespace app\worker\controller;

use app\common\model\ShareEntrust;
use app\common\model\ShareStrategy;
use think\Cache;
use think\Db;
use think\Log;
use think\worker\Server;
use Workerman\Lib\Timer;
 
class Stock extends Server
{
    //只启用一个进程，默认四个
    protected $processes = 1;
 
    /**
     * 每个进程启动
     * @param $worker
     */
    public function onWorkerStart($worker)
    {
        echo date('Y-m-d H:i:s') . " start.\n";
        // 实时获取腾讯接口股票信息
        $this->updateStockInfo();
        // 实时获取证券交易指数信息
        $this->getStockExponentInfo();
        // 监听价格变动 完成委托
        $this->updateEntrustOrder();
    }

    /**
     * 获取股票指数信息
     */
    public function getStockExponentInfo()
    {
        $time_interval = 10;
        $keyExponentInfo = 'stock:hash:exponent';

        $redis = Cache::store('redis')->handler();
        Timer::add($time_interval,function () use ($redis,$keyExponentInfo){
            $url = "https://qt.gtimg.cn?rn=1520407404627&q=s_sh000001,s_sz399001,s_sz399006";
            $res = $this->https_request($url);
            //转换字符编码
            $res = iconv('GBK', 'UTF-8', $res);
            $resData = array_filter(explode("\n", $res));
            echo date('Y-m-d H:i:s') . " Exponent...\n";
            foreach ($resData as $k => $v) 
            {
                $v = explode('~', $v);
                $name = $v[1];
                $no   = $v[2];
                $price = $v[3];
                $px_change = $v[4];
                $px_change_rate = $v[5];
                if( strlen($no) < 6  ) continue;
                $redis->hset($keyExponentInfo, $no, "$no|$name|$price|$px_change|$px_change_rate");
            }
        });
        
    }
 
    /**
     * 更新股票最新信息
     */
    public function updateStockInfo()
    {
        //每5秒执行一次
        $time_interval = 5;
    
        $redis = Cache::store('redis')->handler();
        $stockListKey = 'stock:hash:pricelist';

        if($redis->exists($stockListKey) == false){
            
            $mapStockCodeList = Db::name('stock')->column('id','all_no');
            if( empty( $mapStockCodeList) == false ){
                $redis->hmset($stockListKey, $mapStockCodeList);
            }
        }
        
        //function方法，use从外部引入变量
        Timer::add($time_interval,function () use ($redis,$stockListKey){
            echo date('Y-m-d H:i:s') . " StockInfo...\n";
            // 所有的股票编码
            $allHashKeys = $redis->hkeys($stockListKey);
            $total = $redis->hlen($stockListKey); 
            $limit = ceil($total / 100);
            for ($i = 1; $i <= 100; $i++) {
		
                $slice = array_slice($allHashKeys, ($i-1)*$limit, $limit);
                
                $url = 'http://qt.gtimg.cn/q=' .implode(',',$slice);
                $res = $this->https_request($url);
                //转换字符编码
                $res = iconv('GBK', 'UTF-8', $res);
                $resData = array_filter(explode("\n", $res));
                
                foreach ($resData as $k => $v) 
                {
                    $v = explode('~', $v);
                    $allNo = $slice[$k];
                    $name = $v[1];
                    $no   = $allNo;
                    $price = $v[3];
                    $zf = $v[32];
                    $limitUpPrice = $v[47];
                    $limitDownPrice = $v[48];
                    // 股票编码、名称、价格、涨幅、涨停价、跌停价
                    $content = "$no|$name|$price|$zf|$limitUpPrice|$limitDownPrice";
                    $redis->hset($stockListKey, $allNo, $content);
                }
            }
        });
    }
 
    /**
     * 处理委托订单
     */
    public function updateEntrustOrder()
    {
        //每5秒执行一次
        $time_interval = 5;
        // 有效时间
        $expire_time = 300;

        $redis = Cache::store('redis')->handler();
        Timer::add($time_interval,function () use ($redis,$expire_time){
            echo date('Y-m-d H:i:s') . " Entrust...\n";
            // 从redis取出所有待处理的委托
            $waitHandleKey = 'entrust:list:waitdeal';
            if( $redis->llen($waitHandleKey) ){
                while ($entrustOrder = $redis->rpop($waitHandleKey)) 
                {
                    list($allNo,$dealPrice,$createTime,$eId) = explode('-',$entrustOrder);

                    $price = getActualTimeStockInfoByCode($allNo,'price');
                    echo '处理委托:' .$entrustOrder . "开始...\n";
                    //echo $dealPrice . '|' .$price;
                    if( $dealPrice != $price ){
                        // 现价和委托价格不相同 处理委托过期情况
                        if( time() - $createTime >= $expire_time ){
                            $ent = ShareEntrust::get($eId);
                            $ent->revoke();
                        }
                        continue;
                    }
                    Db::startTrans();
                    try {
                        // 修改委托为"成交"状态
                        $ent = ShareEntrust::get($eId);
                        $ent->status = 2;
                        $ent->updatetime = time();
                        $ent->save();
                        // 判断是买入和卖出
                        if( $ent->mode == 'buy' ){
                            $where = [
                                'user_id' => $ent->user_id,
                                'all_no'  => $ent->all_no,
                                'status'  => 1
                            ];
                            $rows = ShareStrategy::where($where)->find();
                            if( !$rows ){
                                $strategyModel = new ShareStrategy();
                                $params = [
                                    'num'     => $ent->num,
                                    'price'   => $ent->deal_price,
                                    'user_id' => $ent->user_id,
                                    'all_no'  => $ent->all_no,
                                    'name'    => $ent->getData('name'),
                                    'is_auto' => $ent->is_auto
                                ];
                                $strategyModel->newStrategy($params);
                            }else{
                                $strategyModel = new ShareStrategy();
                                $params = [
                                    'num'     => $ent->num,
                                    'price'   => $ent->deal_price,
                                    'user_id' => $ent->user_id,
                                    'all_no'  => $ent->all_no,
                                    'is_auto' => $ent->is_auto
                                ];
                                $strategyModel->appendStrategy($params);
                            }
                            
                        }else if($ent->mode == 'sell'){   // 卖出
                            // 成交委托平仓
                            $strategyModel = new ShareStrategy();
                            $params = [
                                'num'     => $ent->num,
                                'price'   => $ent->deal_price,
                            ];
                            $strategyModel->pay($params);
                        }
                        Db::commit();   
                    } catch (\Exception $th) {
                        Log::record('自动委托：'.$th->getMessage() . '|' . $th->getLine(). '|' . $th->getFile());
                    }
                }
            }
        });
        
    }

    /**
     * http请求方法
     */
    public function https_request($url,$data = null){
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
        if (!empty($data)){
            curl_setopt($curl, CURLOPT_POST, 1);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        }
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($curl);
        curl_close($curl);
        return $output;
    }

    protected function checkWorkTime()
    {
        //判断是否在交易时间段
        $h = date('H');
        if( $h < 9 || $h > 21 ){
            echo 'sleep....start';
            sleep(3600);
            echo 'sleep....end';
        }
    }
}